package com.supermarket.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.supermarket.mapper.DashboardMapper;
import com.supermarket.service.DashboardService;
import com.supermarket.vo.DashboardDataVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.supermarket.constant.RedisConstant.*;

@Service
@Slf4j
@RequiredArgsConstructor
public class DashboardServiceImpl implements DashboardService {

    private final DashboardMapper dashboardMapper;
    private final StringRedisTemplate redisTemplate;

    @Override
    public DashboardDataVo getDashboardData() {
        // 获取今天的开始和结束时间
        LocalDateTime todayStart = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
        LocalDateTime todayEnd = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);

        // 获取7天前的时间
        LocalDateTime sevenDaysAgo = todayStart.minusDays(7);

        // 获取30天前的时间（用于统计热销商品）
        LocalDateTime thirtyDaysAgo = todayStart.minusDays(30);

        return DashboardDataVo.builder()
                .todayOrderCount(getTodayOrderCount(todayStart, todayEnd))
                .todaySales(getTodaySales(todayStart, todayEnd))
                .totalUserCount(getTotalUserCount())
                .totalProductCount(getTotalProductCount())
                .last7DaysSales(getLast7DaysSales(sevenDaysAgo))
                .categoryProductCount(getCategoryProductCount())
                .topSellingProducts(getTopSellingProducts(thirtyDaysAgo))
                .build();
    }

    private Integer getTodayOrderCount(LocalDateTime start, LocalDateTime end) {
        String cachedCount = redisTemplate.opsForValue().get(CACHE_TODAY_ORDER_COUNT);
        if (cachedCount != null) {
            return Integer.valueOf(cachedCount);
        }

        Integer count = dashboardMapper.getTodayOrderCount(start, end);
        redisTemplate.opsForValue().set(CACHE_TODAY_ORDER_COUNT, String.valueOf(count), 5, TimeUnit.MINUTES);
        return count;
    }

    private java.math.BigDecimal getTodaySales(LocalDateTime start, LocalDateTime end) {
        String cachedSales = redisTemplate.opsForValue().get(CACHE_TODAY_SALES);
        if (cachedSales != null) {
            return new java.math.BigDecimal(cachedSales);
        }

        java.math.BigDecimal sales = dashboardMapper.getTodaySales(start, end);
        redisTemplate.opsForValue().set(CACHE_TODAY_SALES, sales.toString(), 5, TimeUnit.MINUTES);
        return sales;
    }

    private Integer getTotalUserCount() {
        String cachedCount = redisTemplate.opsForValue().get(CACHE_TOTAL_USER);
        if (cachedCount != null) {
            return Integer.valueOf(cachedCount);
        }

        Integer count = dashboardMapper.getTotalUserCount();
        redisTemplate.opsForValue().set(CACHE_TOTAL_USER, String.valueOf(count), 30, TimeUnit.MINUTES);
        return count;
    }

    private Integer getTotalProductCount() {
        String cachedCount = redisTemplate.opsForValue().get(CACHE_TOTAL_PRODUCT);
        if (cachedCount != null) {
            return Integer.valueOf(cachedCount);
        }

        Integer count = dashboardMapper.getTotalProductCount();
        redisTemplate.opsForValue().set(CACHE_TOTAL_PRODUCT, String.valueOf(count), 30, TimeUnit.MINUTES);
        return count;
    }

    private List<Map<String, Object>> getLast7DaysSales(LocalDateTime startTime) {
        String cachedData = redisTemplate.opsForValue().get(CACHE_LAST_7DAYS_SALES);
        if (cachedData != null) {
            return JSON.parseObject(cachedData, new TypeReference<List<Map<String, Object>>>(){});
        }

        List<Map<String, Object>> data = dashboardMapper.getLast7DaysSales(startTime);
        redisTemplate.opsForValue().set(CACHE_LAST_7DAYS_SALES, JSON.toJSONString(data), 5, TimeUnit.MINUTES);
        return data;
    }

    private List<Map<String, Object>> getCategoryProductCount() {
        String cachedData = redisTemplate.opsForValue().get(CACHE_CATEGORY_PRODUCT);
        if (cachedData != null) {
            return JSON.parseObject(cachedData, new TypeReference<List<Map<String, Object>>>(){});
        }

        List<Map<String, Object>> data = dashboardMapper.getCategoryProductCount();
        redisTemplate.opsForValue().set(CACHE_CATEGORY_PRODUCT, JSON.toJSONString(data), 30, TimeUnit.MINUTES);
        return data;
    }

    private List<Map<String, Object>> getTopSellingProducts(LocalDateTime startTime) {
        String cachedData = redisTemplate.opsForValue().get(CACHE_TOP_SELLING);
        if (cachedData != null) {
            return JSON.parseObject(cachedData, new TypeReference<List<Map<String, Object>>>(){});
        }

        List<Map<String, Object>> data = dashboardMapper.getTopSellingProducts(startTime);
        redisTemplate.opsForValue().set(CACHE_TOP_SELLING, JSON.toJSONString(data), 30, TimeUnit.MINUTES);
        return data;
    }

    /**
     * 每两个小时执行一次，更新缓存中的数据
     */
    @Scheduled(cron = "0 0 */2 * * ?")  // 每两个小时执行一次
    public void refreshCache() {
        log.info("Refreshing cache...");

        // 更新今天的订单数缓存
        redisTemplate.delete(CACHE_TODAY_ORDER_COUNT);

        // 更新今天的销售额缓存
        redisTemplate.delete(CACHE_TODAY_SALES);

        // 更新总用户数缓存
        redisTemplate.delete(CACHE_TOTAL_USER);

        // 更新总商品数缓存
        redisTemplate.delete(CACHE_TOTAL_PRODUCT);

        // 更新最近7天销售数据缓存
        redisTemplate.delete(CACHE_LAST_7DAYS_SALES);

        // 更新商品分类数据缓存
        redisTemplate.delete(CACHE_CATEGORY_PRODUCT);

        // 更新热销商品数据缓存
        redisTemplate.delete(CACHE_TOP_SELLING);

        // 重新加载数据到缓存
        getTodayOrderCount(LocalDateTime.now(), LocalDateTime.now());
        getTodaySales(LocalDateTime.now(), LocalDateTime.now());
        getTotalUserCount();
        getTotalProductCount();
        getLast7DaysSales(LocalDateTime.now().minusDays(7));
        getCategoryProductCount();
        getTopSellingProducts(LocalDateTime.now().minusDays(30));

        log.info("缓存刷新完成");
    }
}
